package com.xm.data.task;

import com.alibaba.fastjson2.JSONObject;
import com.xm.common.entity.dto.Client;
import com.xm.common.entity.vo.response.RuntimeHistoryVO;
import com.xm.data.entiry.HistoryData;
import com.xm.data.entiry.StatType;
import com.xm.data.service.HistoryDataService;
import com.xm.data.utils.InfluxDbUtils;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;

@Component
@EnableScheduling
public class DataTask {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private InfluxDbUtils influxDbUtils;

    @Resource
    private HistoryDataService historyService;



    @Scheduled(cron = "0 * * * * ?")
    public void taskEvery1Minute() {
        processTaskWithGranularity(1, "-1m");
    }

    @Scheduled(cron = "0 0/5 * * * ?")
    public void taskEvery5Minutes() {
        processTaskWithGranularity(5, "-5m");
    }

    @Scheduled(cron = "0 0/10 * * * ?")
    public void taskEvery10Minutes() {
        processTaskWithGranularity(10, "-10m");
    }

    @Scheduled(cron = "0 0/20 * * * ?")
    public void taskEvery20Minutes() {
        processTaskWithGranularity(20, "-20m");
    }

    @Scheduled(cron = "0 0 * * * ?")
    public void taskEvery1Hour() {
        processTaskWithGranularity(60, "-1h");
    }

    @Scheduled(cron = "0 0 0/2 * * ?")
    public void taskEvery2Hours() {
        processTaskWithGranularity(120, "-2h");
    }

    @Scheduled(cron = "0 0 0/6 * * ?")
    public void taskEvery6Hours() {
        processTaskWithGranularity(360, "-6h");
    }

    @Scheduled(cron = "0 0 0/12 * * ?")
    public void taskEvery12Hours() {
        processTaskWithGranularity(720, "-12h");
    }

    public Map<String, Client> getAllClient() {
        return redisTemplate.<String, Client>opsForHash().entries("clientTokenCache");
    }

    /**
     * 通用任务处理方法
     * @param granularityMinutes 时间粒度（分钟）
     * @param timeRange InfluxDB查询时间范围
     */
    private void processTaskWithGranularity(int granularityMinutes, String timeRange) {
        List<Client> clients = getAllClient().values().stream().toList();

        clients.parallelStream().forEach(client -> {
            RuntimeHistoryVO historyVO = influxDbUtils.readRuntimeData(client.getId(), timeRange);
            List<JSONObject> jsonObjects = historyVO.getList();
            if (jsonObjects.isEmpty()) return;

            long roundedTimestamp = roundTimestamp(LocalDateTime.now(), granularityMinutes);

            Map<StatType, HistoryData> statsMap = calculateAllStats(jsonObjects);

            // 按统计类型存储
            statsMap.forEach((statType, data) -> {
                data.setClientId(client.getId());
                data.setTimestamp(roundedTimestamp);

                // 批量存储（单个数据也包装成List）
                historyService.bulkSave(Collections.singletonList(data), statType, granularityMinutes);
            });
        });
    }

    /**
     * 计算所有统计类型的指标值
     */
    private Map<StatType, HistoryData> calculateAllStats(List<JSONObject> jsonObjects) {
        Map<StatType, HistoryData> statsMap = new EnumMap<>(StatType.class);

        // 初始化各统计类型的HistoryData
        for (StatType type : StatType.values()) {
            if(type == StatType.MIN){
                HistoryData historyData = new HistoryData();
                historyData.setCpuUsage(Double.MAX_VALUE);
                historyData.setMemoryUsage(Double.MAX_VALUE);
                historyData.setDiskUsage(Double.MAX_VALUE);
                historyData.setNetworkUpload(Double.MAX_VALUE);
                historyData.setNetworkDownload(Double.MAX_VALUE);
                historyData.setDiskWrite(Double.MAX_VALUE);
                historyData.setDiskRead(Double.MAX_VALUE);
                statsMap.put(type, historyData);
            } else {
                statsMap.put(type, new HistoryData());
            }
        }

        // 遍历数据，累积统计值
        for (JSONObject json : jsonObjects) {
            double cpu = json.getDouble("cpuUsage");
            double memory = json.getDouble("memoryUsage");
            double disk = json.getDouble("diskUsage");
            double upload = json.getDouble("networkUpload");
            double download = json.getDouble("networkDownload");
            double diskRead = json.getDouble("diskRead");
            double diskWrite = json.getDouble("diskWrite");

            // 更新AVG/SUM统计
            updateStats(statsMap.get(StatType.AVG), cpu, memory, disk, upload, download, diskRead, diskWrite, StatType.AVG);
            updateStats(statsMap.get(StatType.SUM), cpu, memory, disk, upload, download, diskRead, diskWrite, StatType.SUM);

            // 更新MAX/MIN统计
            updateMinMax(statsMap.get(StatType.MAX), cpu, memory, disk, upload, download, diskRead, diskWrite, StatType.MAX);
            updateMinMax(statsMap.get(StatType.MIN), cpu, memory, disk, upload, download, diskRead, diskWrite, StatType.MIN);

            // 记录LAST值（最后一个数据）
            HistoryData lastData = statsMap.get(StatType.LAST);
            lastData.setCpuUsage(cpu);
            lastData.setMemoryUsage(memory);
            lastData.setDiskUsage(disk);
            lastData.setNetworkUpload(upload);
            lastData.setNetworkDownload(download);
            lastData.setDiskRead(diskRead);
            lastData.setDiskWrite(diskWrite);
        }

        // 计算平均值
        int count = jsonObjects.size();
        HistoryData avgData = statsMap.get(StatType.AVG);
        avgData.setCpuUsage(avgData.getCpuUsage() / count);
        avgData.setMemoryUsage(avgData.getMemoryUsage() / count);
        avgData.setDiskUsage(avgData.getDiskUsage() / count);
        avgData.setNetworkUpload(avgData.getNetworkUpload() / count);
        avgData.setNetworkDownload(avgData.getNetworkDownload() / count);
        avgData.setDiskRead(avgData.getDiskRead() / count);
        avgData.setDiskWrite(avgData.getDiskWrite() / count);

        return statsMap;
    }

    /**
     * 更新极值型统计（MAX/MIN）
     */
    private void updateMinMax(HistoryData data, double cpu, double memory, double disk, double upload, double download, double diskRead, double diskWrite, StatType type) {
        if (type == StatType.MAX) {
            data.setCpuUsage(Math.max(data.getCpuUsage(), cpu));
            data.setMemoryUsage(Math.max(data.getMemoryUsage(), memory));
            data.setDiskUsage(Math.max(data.getDiskUsage(), disk));
            data.setNetworkUpload(Math.max(data.getNetworkUpload(), upload));
            data.setNetworkDownload(Math.max(data.getNetworkDownload(), download));
            data.setDiskRead(Math.max(data.getDiskRead(), diskRead));
            data.setDiskWrite(Math.max(data.getDiskWrite(), diskWrite));
        } else {
            data.setCpuUsage(Math.min(data.getCpuUsage(), cpu));
            data.setMemoryUsage(Math.min(data.getMemoryUsage(), memory));
            data.setDiskUsage(Math.min(data.getDiskUsage(), disk));
            data.setNetworkUpload(Math.min(data.getNetworkUpload(), upload));
            data.setNetworkDownload(Math.min(data.getNetworkDownload(), download));
            data.setDiskRead(Math.min(data.getDiskRead(), diskRead));
            data.setDiskWrite(Math.min(data.getDiskWrite(), diskWrite));
        }
    }

    /**
     * 更新累加型统计（AVG/SUM）
     */
    private void updateStats(HistoryData data, double cpu, double memory, double disk, double upload, double download, double diskRead, double diskWrite, StatType type) {
        data.setCpuUsage(data.getCpuUsage() + cpu);
        data.setMemoryUsage(data.getMemoryUsage() + memory);
        data.setDiskUsage(data.getDiskUsage() + disk);
        data.setNetworkUpload(data.getNetworkUpload() + upload);
        data.setNetworkDownload(data.getNetworkDownload() + download);
        data.setDiskRead(data.getDiskRead() + diskRead);
        data.setDiskWrite(data.getDiskWrite() + diskWrite);
    }

    /**
     * 时间戳取整
     */
    private long roundTimestamp(LocalDateTime time, int granularityMinutes) {
        // 1. 使用系统默认时区计算时间戳
        ZoneId systemZone = ZoneId.systemDefault();
        long seconds = time.atZone(systemZone).toEpochSecond();

        // 2. 按粒度取整
        long roundedSeconds = (seconds / (granularityMinutes * 60L)) * (granularityMinutes * 60L);
        return roundedSeconds * 1000; // 转为毫秒时间戳
    }
}